import com.arcadedb.database.Database;
import com.arcadedb.database.DatabaseFactory;
import com.arcadedb.schema.Schema;
import com.arcadedb.schema.Type;
import com.arcadedb.schema.VertexType;
import indi.hjhk.log.Logger;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;

public class ArcadeTSDBServer {
    public static final int SERVER_PORT = 8809;

    public static final String TYPE_OBJECT = "object";
    public static final String PROP_OBJECT_ID = "_objectid";
    public static final int SHOW_MESSAGE_LENGTH = 1000;

    public static HashMap<String, Database> databaseInstances = new HashMap<>();

    public static void main(String[] args) {
        Logger logger = Logger.getPureLogger("TSDBServer");
        
        logger.logSilent("ArcadeTSDB server log");

        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            for (Database database : databaseInstances.values()){
                database.close();
            }
            logger.logOnStdout("server shutdown.");
        }));

        ServerSocket sSocket;
        try {
            sSocket = new ServerSocket(SERVER_PORT);
        } catch (IOException e) {
            logger.logOnStderr("failed to start server socket at port %d", SERVER_PORT);
            throw new RuntimeException(e);
        }
        logger.logOnStdout("server socket start at port %d", SERVER_PORT);

        while (true){
            Socket newSocket = null;
            try {
                newSocket = sSocket.accept();
            } catch (IOException e) {
                logger.logOnStderr("failed to accept new socket");
            }
            if (newSocket != null){
                ArcadeTSDBWorker newWorker = new ArcadeTSDBWorker(newSocket, logger);
                Thread newThread = new Thread(newWorker);
                newThread.start();
            }
        }
    }

    public static Database getOrCreateDatabase(String dbName){
        Database database = databaseInstances.get(dbName);
        if (database != null) return database;
        DatabaseFactory dbf = new DatabaseFactory("./databases/"+dbName);
        if (dbf.exists()){
            database = dbf.open();
        }else{
            database = dbf.create();
        }

        // check object type
        database.begin();
        if (!database.getSchema().existsType(TYPE_OBJECT)){
            VertexType objectType = database.getSchema().createVertexType(TYPE_OBJECT, 32);
            objectType.createProperty(PROP_OBJECT_ID, Type.STRING).createIndex(Schema.INDEX_TYPE.LSM_TREE, true);
        }
        database.commit();

        databaseInstances.put(dbName, database);
        return database;
    }
}
